<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <script>
        var G_num = 5;
        var tableObj;
        var turn = [0, 1, "→", 1, 0, "↓", 0, -1, "←", -1, 0, "↑", ];
        var turnNoteHis = new Array();
        //每个格子是一个节点
        function Node() {
            this.x = 0;
            this.y = 0;
            this.frozen = 0;
            this.hadRun = 0;
            this.nextFlag = " ";
            //"□";
        }
        //查看是否所以格子都已经填满
        function checkAll(tableObj) {
            for (let i = 0; i < G_num; ++i) {
                for (let j = 0; j < G_num; ++j) {
                    let tempNode = tableObj[i][j];
                    if (!tempNode.hadRun) {
                        return false;
                    }
                }
            }
            return true;
        }
        //当前格子为中心往四周走
        function turnNote(x, y) {
            //show(tableObj);
            turnNoteHis.push([x, y]);
            //将转向点压入栈
            for (let i = 0, tmpRes = false; i < turn.length; i = i + 3) {
                //每3个为一组转向数据
                tmpRes = getNextNode(x, y, turn[i], turn[i + 1], turn[i + 2]);
                if (tmpRes && (x != tmpRes[0] || y != tmpRes[1])) {
                    //新节点和当前节点不同，则以新转向点为中心递归
                    tmpRes = turnNote(tmpRes[0], tmpRes[1]);
                    if (tmpRes) {
                        return true;
                    } else {
                        //下一转向点四个方向都走不通且没有走完所有格子
                        let tmpNote = turnNoteHis.pop();
                        //最新转向点出栈
                        setNotRun(x, y, turn[i], turn[i + 1], tmpNote[0], tmpNote[1]);
                    }
                }
            }
            //四个方向都走不通，检查是否都已经走过
            if (!checkAll(tableObj)) {
                tableObj[x][y].hadRun = 0;
                return false;
            } else {
                tableObj[x][y].nextFlag = "End";
                return true;
            }
        }
        //节点直走
        function getNextNode(x, y, xStep, yStep, nextFlag) {
            let loopMaxNum = 100;
            //循环次数限制
            let nextX = x;
            let nextY = y;
            let tmpNote = tableObj[x][y];
            tmpNote.nextFlag = nextFlag;
            tmpNote.hadRun = 1;
            while (loopMaxNum) {
                --loopMaxNum;
                //console.log("从第"+nextX+"行、"+nextY+"列往"+nextFlag+"走一步");
                nextX = nextX + xStep;
                nextY = nextY + yStep;
                if (nextX < 0 || nextY < 0 || nextX >= G_num || nextY >= G_num || (tmpNote = tableObj[nextX][nextY]).hadRun) {
                    //超出表格范围或者此方向走到头，该转向，返回上一个格子的坐标
                    return [nextX - xStep, nextY - yStep];
                } else {
                    //标记走过的格子
                    tmpNote.nextFlag = nextFlag;
                    tmpNote.hadRun = 1;
                }
            }
            return false;
        }
        //将2个格子之间的格子都标记为未走过，起始点未更改，终点更改
        function setNotRun(x, y, xStep, yStep, finX, finY) {
            let loopMaxNum = 100;
            //循环次数限制
            let nextX = x;
            let nextY = y;
            let tmpNote;
            while (loopMaxNum) {
                --loopMaxNum;
                nextX = nextX + xStep;
                nextY = nextY + yStep;
                //标记格子为未走过
                tmpNote = tableObj[nextX][nextY];
                tmpNote.nextFlag = " ";
                //"□";
                tmpNote.hadRun = 0;
                if (nextX == finX && nextY == finY) {
                    return true;
                }
            }
            return false;
        }
        //输出结果
        function show(tableObj) {
            let resStr = "";
            for (let i = 0; i < G_num; ++i) {
                for (let j = 0; j < G_num; ++j) {
                    resStr = resStr + tableObj[i][j].nextFlag;
                    document.getElementById("td" + (i + 1) + (j + 1)).innerHTML = tableObj[i][j].nextFlag;
                }
                resStr = resStr + "\n";
            }
            console.log(resStr);
        }
        //初始化整个表格G_num*G_num
        function init() {
            turnNoteHis = new Array();
            tableObj = new Array();
            for (let x = 0; x < G_num; ++x) {
                tableObj[x] = new Array()
                for (let y = 0; y < G_num; ++y) {
                    let tempNode = new Node();
                    let obj = document.getElementById("td" + (x + 1) + (y + 1));
                    if (obj && obj.className == "select") {
                        tempNode.hadRun = 1;
                        tempNode.nextFlag = "■";
                        tempNode.frozen = 1;
                    }
                    tempNode.x = x;
                    tempNode.y = y;
                    tableObj[x][y] = tempNode;
                }
            }
            return tableObj;
        }
        function run() {
            var tableObj = init();
            //show(tableObj)
            //以每个格子为起始点递归
            let isFindRes = false;
            for (let i = 0; i < G_num && !isFindRes; ++i) {
                for (let j = 0; j < G_num && !isFindRes; ++j) {
                    if (tableObj[i][j].frozen)
                        continue;if (turnNote(i, j)) {
                        isFindRes = true;
                        console.log("起始点:" + i + "," + j);
                        document.getElementById("td" + (i + 1) + (j + 1)).className = "startPoin";
                        show(tableObj);
                        return;
                    }
                }
            }
            alert("此局未找到解法！");
        }
        function changSelect(obj) {
            if (obj.className == "select") {
                obj.className = "unSelect";
            } else {
                obj.className = "select";
            }
        }
    </script>
    <style>
        td {
            height: 40px;
            width: 40px;
            background-color: #A2A2A2;
        }

        .select {
            background-color: #000000;
        }

        .unSelect {
            background-color: #A2A2A2;
        }

        .startPoin {
            background-color: #FFFFFF;
        }
    </style>
    <body>
        <table id>
            <tr>
                <td onClick="changSelect(this)" id="td11"></td>
                <td onClick="changSelect(this)" id="td12"></td>
                <td onClick="changSelect(this)" id="td13"></td>
                <td onClick="changSelect(this)" id="td14"></td>
                <td onClick="changSelect(this)" id="td15"></td>
            </tr>
            <tr>
                <td onClick="changSelect(this)" id="td21"></td>
                <td onClick="changSelect(this)" id="td22"></td>
                <td onClick="changSelect(this)" id="td23"></td>
                <td onClick="changSelect(this)" id="td24"></td>
                <td onClick="changSelect(this)" id="td25"></td>
            </tr>
            <tr>
                <td onClick="changSelect(this)" id="td31"></td>
                <td onClick="changSelect(this)" id="td32"></td>
                <td onClick="changSelect(this)" id="td33"></td>
                <td onClick="changSelect(this)" id="td34"></td>
                <td onClick="changSelect(this)" id="td35"></td>
            </tr>
            <tr>
                <td onClick="changSelect(this)" id="td41"></td>
                <td onClick="changSelect(this)" id="td42"></td>
                <td onClick="changSelect(this)" id="td43"></td>
                <td onClick="changSelect(this)" id="td44"></td>
                <td onClick="changSelect(this)" id="td45"></td>
            </tr>
            <tr>
                <td onClick="changSelect(this)" id="td51"></td>
                <td onClick="changSelect(this)" id="td52"></td>
                <td onClick="changSelect(this)" id="td53"></td>
                <td onClick="changSelect(this)" id="td54"></td>
                <td onClick="changSelect(this)" id="td55"></td>
            </tr>
        </table>
        <br>
        <br>
        <button onClick="run();">执行</button>
        <br>
        <br>
        <button onClick="location.reload();">重置</button>
    </body>
</html>
